<?php
/**
 * redis服务类
 * @author hjc19850430@gmail.com
 */
class NewRedisService
{
    private $_instance;

    private function __construct($options = null)
    {

    }

    public static function connectRedis($options = null)
    {
        if (!extension_loaded('redis')) {
            throw_exception(L('_NOT_SUPPERT_') . ':redis');
        }

        
        $defOption = array(
            'host' => C('REDIS_HOST') ? C('REDIS_HOST') : '127.0.0.1',
            'port' => C('REDIS_PORT') ? C('REDIS_PORT') : 6379,
            'timeout' => C('REDIS_CACHE_TIMEOUT') ? C('REDIS_CACHE_TIMEOUT') : false,
            'persistent' => false,
            'expire' => C('REDIS_CACHE_TIMEOUT'),
            'passwd' => C('REDIS_PASS'),
            'select_db' => C('REDIS_DEF_DB'),
        );
        if (!empty($options)) {
            $options = array_merge($defOption,$options);
        } else {
            $options = $defOption;
        }
        
        $func = $options['persistent'] ? 'pconnect' : 'connect';
        $redis = new Redis();
        $connected = $options['timeout'] === false
            ? $redis->$func($options['host'], $options['port'])
            : $redis->$func($options['host'], $options['port'], $options['timeout']);

        if ( !$redis->auth($options['passwd']) ) {
            throw_exception(L('_REDIS_AUTH_ERROR_'));
        }
        
        $redis->select($options['select_db']);
        return $redis;
    }

    /**
     * 初始化主库，做写操作
     */
    public static function initMaster()
    {
        //主从数据库暂时设置成一样的
        $masterOptions = array(
            'host' => C('REDIS_HOST') ? C('REDIS_HOST') : '127.0.0.1',
            'port' => C('REDIS_PORT') ? C('REDIS_PORT') : 6379,
            'timeout' => C('DATA_CACHE_TIMEOUT') ? C('DATA_CACHE_TIMEOUT') : false,
            'persistent' => false,
            'expire' => C('DATA_CACHE_TIME'),
            'passwd' => C('REDIS_PASS'),
            'select_db' => C('REDIS_DEF_DB'),
        );

        return self::connectRedis($masterOptions);
    }

    /**
     * 初始化从库，做读操作
     */
    public  static function initSlave()
    {
        //主从数据库暂时设置成一样的
        $slaveOptions = array(
            'host' => C('REDIS_HOST') ? C('REDIS_HOST') : '127.0.0.1',
            'port' => C('REDIS_PORT') ? C('REDIS_PORT') : 6379,
            'timeout' => C('DATA_CACHE_TIMEOUT') ? C('DATA_CACHE_TIMEOUT') : false,
            'persistent' => false,
            'expire' => C('DATA_CACHE_TIME'),
            'passwd' => C('REDIS_PASS'),
            'select_db' => C('REDIS_DEF_DB'),
        );

        return self::connectRedis($slaveOptions);
    }

    /**
     * 设置字符类型的缓存
     * @param string $key
     * @param mixed $data 数组|字符串
     * @param int   $expire 失效时间
     * @return mixed
     */
    public static function set($key,$data, $expire = null)
    {
        $redisObj = self::initMaster();

        if (is_array($data)) {
            $parseData = json_encode($data,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } else {
            $parseData = $data;
        }

        if (is_numeric($expire)) {
            return $redisObj->setex(self::_key($key, 'string'), $expire, $parseData);
        } else {
            return $redisObj->set(self::_key($key, 'string'), $parseData);
        }
    }

    /**
     * 得到字符串类型的缓存数据
     * @param string $key
     * @return mixed
     */
    public static function get($key, $type='string')
    {
        $redisObj = self::initSlave();
        $data = $redisObj->get(self::_key($key, $type));

        if (!is_numeric($data)) {
            return json_decode($data,true);
        } else {
            return $data;
        }
    }

    /**
     * 数据增量操作
     * @param string $key   操作的那个key
     * @param int $num      新增的值
     * @return mixed
     */
    public static function incr($key, $incrNum=1)
    {
        $redisObj = self::initMaster();

        $incrNum = intval($incrNum);
        if ($incrNum == 1) {
            return $redisObj->incr(self::_key($key, 'string'));
        }
        return $redisObj->incrBy(self::_key($key, 'string'), $incrNum);
    }

    /**
     * 数据做减操作
     * @param type $key
     * @param type $decrNum
     */
    public static function decr($key, $decrNum=1)
    {
        $redisObj = self::initMaster();

        $decrNum = intval($decrNum);
        if ($decrNum == 1) {
            return $redisObj->decr(self::_key($key, 'string'), $decrNum);
        }
        return $redisObj->decrBy(self::_key($key, 'string'), $decrNum);
    }

    /**
     * 对数据量做做增/减操作
     * @param string $key       hash键
     * @param string $fieldName hash键下面的字段名称
     * @param int    $incrNum   做增/减操作的值，如果是减操作就用负数
     */
    public static function hIncr($key, $fieldName, $incrNum)
    {
        $redisObj = self::initMaster();
        $incrNum = intval($incrNum);
        return $redisObj->hIncrBy(self::_key($key, 'hash'), $fieldName, $incrNum);
    }

    /**
     * 设置hash值
     * @param string $key       键
     * @param array $hashVal    值
     * @param int $expire       失效时间戳
     * @return mixed
     */
    public static function hset($key, $hashVal, $expire=null)
    {
        $redisObj = self::initMaster();

        $cacheKey = self::_key($key,'hash');
        $countVal = count($hashVal);
        if ($countVal == 1) {
            $res = $redisObj->hSet($cacheKey, key($hashVal), current($hashVal) );
        } else if ($countVal > 1) {
            $res = $redisObj->hMset($cacheKey, $hashVal);
        }

        if (is_numeric($expire) ) {
            $redisObj->expire($cacheKey,$expire);
        }

        return $res;
    }

    /**
     * 得到hash值
     * @param string $key     键
     * @param mixed $fields   读取的字段
     */
    public static function hget($key, $fields=null, $keyPrefix='hash')
    {
        $redisObj = self::initSlave();

        if ($fields == '*' || is_null($fields)) {
            return $redisObj->hGetAll(self::_key($key,$keyPrefix) );
        } else if (strpos($fields,',') != false) {
            return $redisObj->hMget(self::_key($key,$keyPrefix),explode(',', $fields) );
        } else {
            return $redisObj->hGet(self::_key($key,$keyPrefix), $fields );
        }
    }

    /**
     * 删除数据
     * @param $key
     * @param $type
     */
    public static function rm($key)
    {
        $redisObj = self::initMaster();

        return $redisObj->del($key);
    }

    /**
     * 获得所有的key
     * @param string $key   键名
     * @param string $type  类型 hash|string|list|set
     */
    public static function keys($key,$type="string")
    {
        $redisObj = self::initSlave();
        return $redisObj->keys(self::_key($key,$type));
    }

    /**
     * 判断键是否存在
     * @param string $key 键
     * @return bool
     */
    public static function keyExists($key,$type="string")
    {
        $redisObj = self::initSlave();
        return $redisObj->exists(self::_key($key,$type));
    }

    /**
     * 键值类型
     * @param string $keyName   键名称
     * @param string $keyType   键类型
     * @return string
     */
    protected static function _key($keyName, $keyType)
    {
        if ($keyType) {
            $keyType = $keyType.'_';
        }
        return $keyType.$keyName;
    }
}